package com.rabtman.common.utils;

import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.inputmethod.InputMethodManager;
import java.lang.reflect.Field;

/**
 * <pre>
 *     author: Blankj
 *     blog  : http://blankj.com
 *     time  : 2016/08/02
 *     desc  : utils about keyboard
 * </pre>
 */
public final class KeyboardUtils {

  private static int sContentViewInvisibleHeightPre;

  private KeyboardUtils() {
    throw new UnsupportedOperationException("u can't instantiate me...");
  }

  /**
   * Show the soft input.
   *
   * @param activity The activity.
   */
  public static void showSoftInput(final Activity activity) {
    InputMethodManager imm =
        (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    if (imm == null) {
      return;
    }
    View view = activity.getCurrentFocus();
    if (view == null) {
      view = new View(activity);
    }
    imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
  }

  /**
   * Show the soft input.
   *
   * @param view The view.
   */
  public static void showSoftInput(final View view) {
    InputMethodManager imm =
        (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
    if (imm == null) {
      return;
    }
    view.setFocusable(true);
    view.setFocusableInTouchMode(true);
    view.requestFocus();
    imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
  }

  /**
   * Hide the soft input.
   *
   * @param activity The activity.
   */
  public static void hideSoftInput(final Activity activity) {
    InputMethodManager imm =
        (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    if (imm == null) {
      return;
    }
    View view = activity.getCurrentFocus();
    if (view == null) {
      view = new View(activity);
    }
    imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
  }

  /**
   * Hide the soft input.
   *
   * @param view The view.
   */
  public static void hideSoftInput(final View view) {
    InputMethodManager imm =
        (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
    if (imm == null) {
      return;
    }
    imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
  }

  /**
   * Toggle the soft input display or not.
   */
  public static void toggleSoftInput() {
    InputMethodManager imm =
        (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
    if (imm == null) {
      return;
    }
    imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
  }

  /**
   * Return whether soft input is visible.
   * <p>The minimum height is 200</p>
   *
   * @param activity The activity.
   * @return {@code true}: yes<br>{@code false}: no
   */
  public static boolean isSoftInputVisible(final Activity activity) {
    return isSoftInputVisible(activity, 200);
  }

  /**
   * Return whether soft input is visible.
   *
   * @param activity The activity.
   * @param minHeightOfSoftInput The minimum height of soft input.
   * @return {@code true}: yes<br>{@code false}: no
   */
  public static boolean isSoftInputVisible(final Activity activity,
      final int minHeightOfSoftInput) {
    return getContentViewInvisibleHeight(activity) >= minHeightOfSoftInput;
  }

  private static int getContentViewInvisibleHeight(final Activity activity) {
    final View contentView = activity.findViewById(android.R.id.content);
    Rect outRect = new Rect();
    contentView.getWindowVisibleDisplayFrame(outRect);
    return contentView.getBottom() - outRect.bottom;
  }

  /**
   * Register soft input changed listener.
   *
   * @param activity The activity.
   * @param listener The soft input changed listener.
   */
  public static void registerSoftInputChangedListener(final Activity activity,
      final OnSoftInputChangedListener listener) {
    final View contentView = activity.findViewById(android.R.id.content);
    sContentViewInvisibleHeightPre = getContentViewInvisibleHeight(activity);
    contentView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
      @Override
      public void onGlobalLayout() {
        if (listener != null) {
          int height = getContentViewInvisibleHeight(activity);
          if (sContentViewInvisibleHeightPre != height) {
            listener.onSoftInputChanged(height);
            sContentViewInvisibleHeightPre = height;
          }
        }
      }
    });
  }

  /**
   * Fix the leaks of soft input.
   * <p>Call the function in {@link Activity#onDestroy()}.</p>
   *
   * @param context The context.
   */
  public static void fixSoftInputLeaks(final Context context) {
    if (context == null) {
      return;
    }
    InputMethodManager imm =
        (InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
    if (imm == null) {
      return;
    }
    String[] strArr = new String[]{"mCurRootView", "mServedView", "mNextServedView"};
    for (int i = 0; i < 3; i++) {
      try {
        Field declaredField = imm.getClass().getDeclaredField(strArr[i]);
        if (declaredField == null) {
          continue;
        }
        if (!declaredField.isAccessible()) {
          declaredField.setAccessible(true);
        }
        Object obj = declaredField.get(imm);
        if (obj == null || !(obj instanceof View)) {
          continue;
        }
        View view = (View) obj;
        if (view.getContext() == context) {
          declaredField.set(imm, null);
        } else {
          return;
        }
      } catch (Throwable th) {
        th.printStackTrace();
      }
    }
  }

  /**
   * Click blankj area to hide soft input.
   * <p>Copy the following code in ur activity.</p>
   */
  public static void clickBlankArea2HideSoftInput() {
    Log.i("KeyboardUtils", "Please refer to the following code.");
        /*
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
                View v = getCurrentFocus();
                if (isShouldHideKeyboard(v, ev)) {
                    InputMethodManager imm =
                            (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(v.getWindowToken(),
                            InputMethodManager.HIDE_NOT_ALWAYS
                    );
                }
            }
            return super.dispatchTouchEvent(ev);
        }
        // Return whether touch the view.
        private boolean isShouldHideKeyboard(View v, MotionEvent event) {
            if (v != null && (v instanceof EditText)) {
                int[] l = {0, 0};
                v.getLocationInWindow(l);
                int left = l[0],
                        top = l[1],
                        bottom = top + v.getHeight(),
                        right = left + v.getWidth();
                return !(event.getX() > left && event.getX() < right
                        && event.getY() > top && event.getY() < bottom);
            }
            return false;
        }
        */
  }

  public interface OnSoftInputChangedListener {

    void onSoftInputChanged(int height);
  }
}